package com.yuba.front.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HtmlUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuba.common.core.constant.ActionTypes;
import com.yuba.common.core.constant.Constants;
import com.yuba.common.core.constant.UserConstants;
import com.yuba.common.core.domain.model.MessageMeta;
import com.yuba.common.core.exception.front.CommentException;
import com.yuba.common.core.exception.front.LikeException;
import com.yuba.common.core.utils.MapstructUtils;
import com.yuba.common.core.utils.SpringUtils;
import com.yuba.common.core.utils.StringUtils;
import com.yuba.common.mybatis.core.page.PageQuery;
import com.yuba.common.satoken.utils.LoginHelper;
import com.yuba.front.domain.CommentPosts;
import com.yuba.front.domain.bo.CommentPostsBo;
import com.yuba.front.domain.param.ActionParam;
import com.yuba.front.domain.param.CommentListParam;
import com.yuba.front.domain.param.CommentParam;
import com.yuba.front.domain.vo.CommentPostsVo;
import com.yuba.front.domain.vo.CommentVo;
import com.yuba.front.event.MessageHandleEvent;
import com.yuba.front.event.UnMessageHandleEvent;
import com.yuba.front.event.UpdatePostsEvent;
import com.yuba.front.mapper.CommentPostsMapper;
import com.yuba.front.service.ICommentPostsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * 文章评论Service业务层处理
 *
 * @author modakai
 * @date 2024-12-09
 */
@RequiredArgsConstructor
@Service
public class CommentPostsServiceImpl implements ICommentPostsService {

    private static final int DEFAULT_CHILDREN_PAGE_SIZE = 3;
    private static final String DEFAULT_CHILDREN_ORDER_BY_COLUMN = "comment_posts.create_time";

    private final CommentPostsMapper baseMapper;

    /**
     * 查询文章评论
     *
     * @param commentId 主键
     * @return 文章评论
     */
    @Override
    public CommentPostsVo queryById(Long commentId) {
        return baseMapper.selectVoById(commentId);
    }


    /**
     * 查询符合条件的文章评论列表
     *
     * @param bo 查询条件
     * @return 文章评论列表
     */
    @Override
    public List<CommentPostsVo> queryList(CommentPostsBo bo) {
        LambdaQueryWrapper<CommentPosts> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<CommentPosts> buildQueryWrapper(CommentPostsBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<CommentPosts> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getPostsId() != null, CommentPosts::getPostsId, bo.getPostsId());
        lqw.eq(bo.getUserId() != null, CommentPosts::getUserId, bo.getUserId());
        lqw.eq(bo.getParentId() != null, CommentPosts::getParentId, bo.getParentId());
        lqw.eq(bo.getReplyUserId() != null, CommentPosts::getReplyUserId, bo.getReplyUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), CommentPosts::getContent, bo.getContent());
        lqw.eq(StringUtils.isNotBlank(bo.getTopFlag()), CommentPosts::getTopFlag, bo.getTopFlag());
        lqw.eq(bo.getLikeCount() != null, CommentPosts::getLikeCount, bo.getLikeCount());
        return lqw;
    }

    /**
     * 新增文章评论
     *
     * @param bo 文章评论
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(CommentPostsBo bo) {
        CommentPosts add = MapstructUtils.convert(bo, CommentPosts.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setCommentId(add.getCommentId());
        }
        return flag;
    }

    /**
     * 修改文章评论
     *
     * @param bo 文章评论
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(CommentPostsBo bo) {
        CommentPosts update = MapstructUtils.convert(bo, CommentPosts.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(CommentPosts entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除文章评论信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pushPostsComment(CommentParam body, Long userId) {
        // 1 构建插入实体
        CommentPosts commentPosts = new CommentPosts();
        commentPosts.setPostsId(body.getTargetId());
        commentPosts.setContent(body.getContent());
        commentPosts.setUserId(userId);
        commentPosts.setReplyUserId(body.getReplyUserId());
        commentPosts.setParentId(body.getParentId());
        // 2 插入数据
        int insert = baseMapper.insert(commentPosts);
        if (insert != 1) {
            throw new CommentException("front.comment.push.error");
        }

        // 3 更新文章评论次数 可以使用spring事件触发器
        UpdatePostsEvent event = UpdatePostsEvent.build(body.getTargetId(), ActionTypes.COMMENT, true);
        SpringUtils.context().publishEvent(event);


       if (!userId.equals(body.getReplyUserId())) {
           MessageHandleEvent messageEvent = MessageHandleEvent.builder()
               .type(ActionTypes.COMMENT)
               .userId(body.getReplyUserId())
               .senderId(userId)
               .senderNickname(LoginHelper.getLoginUser().getNickname())
               .message(body.getContent())
               .sourceId(commentPosts.getCommentId())
               .meta(new MessageMeta()
                   .setType(ActionTypes.COMMENT)
                   .setPostsId(body.getTargetId())
                   .setCommentId(commentPosts.getCommentId())
                   .setParentId(body.getParentId() == null ? 0 : body.getParentId())
                   .setContent(body.getParentId() == null ? "" :  HtmlUtil.cleanHtmlTag(body.getReplyContent()))
               )
               .build();
           SpringUtils.context().publishEvent(messageEvent);
       }
    }

    @Override
    public Page<CommentVo> pagePostsList(CommentListParam form) {
        // 自定义分页
        Page<CommentVo> parentPage = form.getPageQuery().build();

        // 如果没有传递parentId，那么就默认查询一级评论
        long parentId = form.getParentId() == null ? 0 : form.getParentId();

        // 查询评论列表
        parentPage = baseMapper.pagePostsList(parentPage, form.getTargetId(), parentId);

        boolean login = LoginHelper.isLogin();
        HashSet<Long> likeCommentIds;
        if (login) {
            likeCommentIds = baseMapper.getLikeCommentIds(LoginHelper.getUserId());
        } else {
            likeCommentIds = new HashSet<>();
        }

        // 设置标识点赞标识
        if (CollectionUtil.isNotEmpty(likeCommentIds)) {
            parentPage.getRecords().forEach(commentVo -> commentVo.setLikeFlag(likeCommentIds.contains(commentVo.getCommentId())));
        }

        if (parentId == 0) {
            // 找子级
            PageQuery childrenPageQuery = form.getPageQuery();
            childrenPageQuery.setOrderByColumn(DEFAULT_CHILDREN_ORDER_BY_COLUMN);
            childrenPageQuery.setPageSize(DEFAULT_CHILDREN_PAGE_SIZE);
            // 默认都只返回前3条
            for (CommentVo commentVo : parentPage.getRecords()) {
                Page<CommentVo> childrenPage = childrenPageQuery.build();
                childrenPage = baseMapper.pagePostsList(childrenPage, form.getTargetId(), commentVo.getCommentId());
                //                 // 设置点赞标识
                if (CollectionUtil.isNotEmpty(likeCommentIds)) {

                    childrenPage.getRecords().forEach(children -> children.setLikeFlag(likeCommentIds.contains(children.getCommentId())));
                }
                commentVo.setChildren(childrenPage);
            }
        }


        return parentPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void likeComment(Long commentId, String type, Long userId) {
        CommentPostsVo commentPostsVo = queryById(commentId);
        // 更新点赞数
        CommentPostsBo commentPostsBo = new CommentPostsBo();
        commentPostsBo.setCommentId(commentId);
        MessageHandleEvent event = null;
        if (ActionTypes.LIKE.equals(type)) {
            commentPostsBo.setLikeCount(commentPostsVo.getLikeCount() + 1);
            String nickname = LoginHelper.getLoginUser().getNickname();
            // 添加消息提醒 userId sourceId type message模板 meta元数据
            if (!userId.equals(commentPostsVo.getUserId())) {
                event = MessageHandleEvent.builder()
                    .type(ActionTypes.LIKE)
                    .userId(commentPostsVo.getUserId())
                    .senderId(userId)
                    .senderNickname(nickname)
                    .sourceId(commentId)
                    .message("点赞了您的评论")
                    .meta(new MessageMeta()
                        .setType(ActionTypes.COMMENT)
                        .setPostsId(commentPostsVo.getPostsId())
                        .setParentId(commentPostsVo.getParentId())
                        .setCommentId(commentId))
                    .build();

                SpringUtils.context().publishEvent(event);
            }

            Boolean update = updateByBo(commentPostsBo);
            if (!update) {
                throw new LikeException("front.like.error");
            }

            // 插入点赞关联数据
            Boolean insert = baseMapper.insertRelation(commentId, userId);
            if (!insert) {
                throw new LikeException("front.like.error");
            }



        } else {
            commentPostsBo.setLikeCount(commentPostsVo.getLikeCount() - 1);
            Boolean update = updateByBo(commentPostsBo);
            if (!update) {
                throw new LikeException("front.like.error");
            }
            // 删除点赞关联数据
            Boolean deleted = baseMapper.deleteRelation(commentId, userId);
            if (!deleted) {
                throw new LikeException("front.like.error");
            }

            if (!userId.equals(commentPostsVo.getUserId())) {
                // 发送取消点赞帖子消息
                UnMessageHandleEvent unMessageHandleEvent = UnMessageHandleEvent.builder()
                    .type(ActionTypes.LIKE)
                    .userId(commentPostsVo.getUserId())
                    .senderId(userId)
                    .sourceId(commentId)
                    .build();

                SpringUtils.context().publishEvent(unMessageHandleEvent);
            }

        }

    }

    @Override
    public void postsCommentTop(ActionParam actionParam, Long userId) {
        // 1. 查询该帖子是否已经存在置顶评论 （只能置顶一级评论）
        // 检测是否存在其他置顶评论
        LambdaQueryWrapper<CommentPosts> lqw = new LambdaQueryWrapper<>();
        lqw.eq(CommentPosts::getPostsId, actionParam.getPostsId())
            .eq(CommentPosts::getTopFlag, UserConstants.YES);
        Long topCount = baseMapper.selectCount(lqw);
        if (topCount > 0) {
            throw new CommentException("front.comment.exist.top.error");
        }
        // 检测是否未一级评论
        CommentPostsVo commentVo = queryById(actionParam.getCommentId());
        if (0 == commentVo.getParentId()) {
            throw new CommentException("front.comment.parent.error");
        }
        // 2. 更新置顶状态
        CommentPostsBo commentPostsBo = new CommentPostsBo();
        commentPostsBo.setCommentId(actionParam.getCommentId());
        if (ActionTypes.COMMENT_TOP.equals(actionParam.getType())) {
            commentPostsBo.setTopFlag(UserConstants.YES);
        } else {
            commentPostsBo.setTopFlag(Constants.NO);
        }
        Boolean update = updateByBo(commentPostsBo);
        if (!update) {
            throw new CommentException("front.comment.top.error");
        }

    }

    @Override
    public void postsCommentDelete(ActionParam actionParam, Long userId) {
        // 校验要删除的评论的用户id 是否为当前用户的id
        LambdaQueryWrapper<CommentPosts> lqw = new LambdaQueryWrapper<>();
        lqw.eq(CommentPosts::getCommentId, actionParam.getCommentId())
            .eq(CommentPosts::getUserId, userId);
        Long topCount = baseMapper.selectCount(lqw);
        if (topCount == 0) {
            throw new CommentException("front.comment.delete.error");
        }

        // 删除
        deleteWithValidByIds(List.of(actionParam.getCommentId()), false);

//        if (!userId.equals(actionParam.getAuthorId())) {
//            // 发送取消点赞帖子消息
//            UnMessageHandleEvent unMessageHandleEvent = UnMessageHandleEvent.builder()
//                .type(ActionTypes.COMMENT)
//                .userId(actionParam.getCommentId())
//                .senderId(userId)
//                .sourceId(actionParam.getPostsId())
//                .build();
//
//            SpringUtils.context().publishEvent(unMessageHandleEvent);
//        }
    }


}
